import { Controller, Get, Req, Inject, BadRequestException, HttpStatus, HttpException } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';

import { SmsCaptchaService } from './sms-captcha.service';
import { SkipAuth, SkipLogin } from 'src/common/decorator/public.decorator';
import { ConfigService } from '@nestjs/config';
import { decrypt, getRedisKey, validateEmail, validatePhone } from 'src/utils';
import { IDENTITY, SMS_TYPE, VERIFIED_UPDATE_TYPE } from 'src/utils/config';

@Controller('sms-captcha')
export class SmsCaptchaController {
    constructor(
        @Inject(CACHE_MANAGER) private cacheManager: Cache,
        private smsCaptchaService: SmsCaptchaService,
        private configService: ConfigService,
    ) { }

    // 图形验证码
    @SkipLogin()
    @Get('/captcha')
    async createImageCaptcha(@Req() req: Request | any) {
        // 不用引用Res，nestjs会拦截的
        const { slug = '' } = req.query || {};
        const account = await this.smsCaptchaService.getSmsAccount(req?.user?.userId, req.query);

        const { data, text } = this.smsCaptchaService.createExpr();
        const captchaRedisKey = getRedisKey(account, slug, 'captcha'); // 表达式结果存入Redis
        await this.cacheManager.store.set(captchaRedisKey, text, this.configService.get('SMS_EXPIRE')); // 单位毫秒；5分钟，和短信验证码一样

        return data;
    }

    @SkipLogin()
    @Get('/sms')
    async sendSms(@Req() req: Request | any) {
        const { userId } = req.user || {};
        const { phone = '', email = '', identity = '', slug = '', captcha = '' } = req.query || {};
        const smsTtl = this.configService.get('SMS_EXPIRE');

        // 基础参数逻辑校验
        if (!slug) throw new BadRequestException(`类型不能为空`);
        if (!SMS_TYPE.includes(slug)) throw new BadRequestException(`类型错误，支持类型：(${SMS_TYPE.join(',')})`);
        if (identity) {
            if (!IDENTITY.includes(identity)) throw new BadRequestException(`身份类型错误，支持类型：(${IDENTITY.join(',')})`);
        } else {
            if (!phone && !email) throw new BadRequestException(`账号不能为空`);
            if (phone && !validatePhone(phone)) throw new BadRequestException(`手机号格式错误`);
            if (email && !validateEmail(email)) throw new BadRequestException(`邮箱格式错误`);
        }
        // 获取账号
        const account = await this.smsCaptchaService.getSmsAccount(userId, req.query);
        // 是否已发送，还未过期
        await this.smsCaptchaService.rateCheck(account, slug);
        // 账号是否已冻结
        await this.smsCaptchaService.frozenCheck(account, slug);
        // 是否错误过，如果错误过就需要弹图形验证码
        const needCaptcha = await this.smsCaptchaService.useCaptchaCheck(account, slug);
        if (needCaptcha && !captcha) throw new HttpException(`图形验证码不能为空`, HttpStatus.PARTIAL_CONTENT);
        // 校验图形验证码是否正确
        if (needCaptcha && captcha) await this.smsCaptchaService.captchaCheck(account, slug, captcha);
        // 身份验证是否通过
        if (VERIFIED_UPDATE_TYPE.includes(slug)) await this.smsCaptchaService.identityCheck(userId, slug);
        // 生成短信验证码
        const smsCode = await this.smsCaptchaService.createSms(account);
        // 记录发送次数
        const limitKey = getRedisKey(account, slug, 'limit');
        const currentLimit: number = await this.cacheManager.store.get(limitKey) || 0;
        await this.cacheManager.store.set(limitKey, currentLimit + 1, smsTtl);
        // 结果存放到Redis里
        const smsKey = getRedisKey(account, slug, 'sms');
        await this.cacheManager.store.set(smsKey, smsCode, smsTtl); // 单位毫秒；5分钟，和图形验证码一样
        // 销毁图形验证码
        const captchaRedisKey = getRedisKey(account, slug, 'captcha');
        await this.cacheManager.store.del(captchaRedisKey);

        return '验证码已发送';
    }
}
